/*
  config.c
  Achieve the config moudle
  BeginnerC
 */
#include "config.h"
/*
  ReadLine
    Read a line to the buffer
    buffer
      The buffer to store the string
    buffer_length
      The max length of the buffer
    fp
      The pointer to the file
  Return Value
    The read length
  BeginnerC
 */
int ReadLine(char buffer[], int buffer_length, FILE *fp)
{
    int read_length = 0;
    fgets(buffer, buffer_length, fp);
    read_length = strlen(buffer) - 1;
    if ('\n' == buffer[read_length])
    {
        buffer[read_length] = '\0';
    }
    return read_length;
}
/*
  AnalyseLine
    Analyse a text line to a config item
  Argument
    line
      The text line
  Return Value
    The pointer to the analysed result
    NULL Failed
  BeginnerC
 */
ConfigItem *AnalyseLine(const char *line)
{
    ConfigItem *item = NULL;
    int c = 0;
    unsigned position = 0, temp = 0;
    if (NULL == line)
    {
        return NULL;
    }
    item = (ConfigItem*)calloc(1, sizeof(ConfigItem));
    if (NULL == item)
    {
        return NULL;
    }
    c = *line;
    while (c != '=')
    {
        position++;
        c = *(line + position);
    }
    temp = position;
    c = *(line + position - 1);
    while (c == ' ')
    {
        position--;
        c = *(line + position - 1);
    }
    strncpy(item -> key, line, position);
    position = temp + 1;
    c = *(line + position);
    while (c == ' ')
    {
        position++;
        c = *(line + position);
    }
    strcpy(item -> value, line + position);
    return item;
}
/*
  AddConfigItem
    Add item to the config list
  Argument
    config
      The list to store the config item
    item
      The item want to be add
  Return Value
    0 Success
    -1 Failed
  BeginnerC
 */
int AddConfigItem(Config *config, ConfigItem *item)
{
    if (NULL == config || NULL == item)
    {
        return -1;
    }
    if (NULL == config -> first)
    {
        config -> first = item;
        config -> last = item;
    }
    else
    {
        config -> last -> next = item;
        config -> last = item;
    }
    return 0;
}
/*
  FreeConfig
    Free the memory of the config list
  Argument
    config
      The list to store the config item
  Return Value
    0 Success
    -1 Failed
  BeginnerC
 */
int FreeConfig(Config *config)
{
    ConfigItem *item = NULL, *temp = NULL;
    if (NULL == config)
    {
        return -1;
    }
    item = config -> first;
    while (item)
    {
        temp = item -> next;
        free(item);
        item = temp;
    }
    free(config);
    return 0;
}
/*
  InitConfig
    Init the config list
  Argument
    No argument required
  Return Value
    Equal to calloc function, ConfigItem* type
  BeginnerC
 */
Config* InitConfig()
{
    return (Config*)calloc(1, sizeof(Config));
}
/*
  LoadConfig
    Load the config file
  Argument
    file_name
      The full path or the file name of the config file
  Return Value
    The pointer to the config
    NULL Failed
  BeginnerC
 */
Config* LoadConfig(const char *file_name)
{
    FILE *fp = NULL;
    Config* config = NULL;
    config = InitConfig();
    if (NULL == config)
    {
        return NULL;
    }
    fp = fopen(file_name, "r");
    if (NULL == fp)
    {
        FreeConfig(config);
        return NULL;
    }
    while(!feof(fp))
    {
        char buffer[1024] = {};
        ConfigItem *item = NULL;
        ReadLine(buffer, 1024, fp);
        /* Ignore the config comment  */
        if ('#' != *buffer)
        {
            item = AnalyseLine(buffer);
            if (NULL == item)
            {
                FreeConfig(config);
                return NULL;
            }
            if (-1 == AddConfigItem(config, item))
            {
                FreeConfig(config);
                return NULL;
            }
        }
    }
    fclose(fp);
    return config;
}
/*
  QueryConfig
    Query the value of the key
  Argument
    config
      The pointer to the key
    key
      The key point to the value
  Return Value
    The value's value
    NULL Failed
  BeginnerC
 */
char* QueryConfig(Config *config,const char *key)
{
    ConfigItem *item = NULL, *temp = NULL;
    char *result = NULL;
    if (NULL == config)
    {
        return NULL;
    }
    item = config -> first;
    while (item)
    {
        temp = item -> next;
        if (!strcmp(key, item -> key))
        {
            result = item -> value;
            break;
        }
        item = temp;
    }
    return result;
}
